#include "app_config.h"
#include "app_music.h"
#include "system/sys_common.h"
#include "server/rt_stream_pkg.h"
#include "stream_core.h"
#include "sock_api/sock_api.h"
#include "get_yuv_data.h"

#ifdef CONFIG_VIDEO_ENABLE

#include "motion_detect.h"
#ifdef CONFIG_QR_CODE_NET_CFG
#include "asm/jpeg_codec.h"
#include "qrcode/qrcode.h"
#include "json_c/json_tokener.h"
#include "mbedtls/base64.h"
#endif

extern int qr_code_net_set_ssid_pwd(const char *ssid, const char *pwd);
extern int page_turning_recognition(void *data, u32 length, u8 buf_copy);
extern u8 page_turning_get_mode(void);
extern u8 get_turing_ocr_flag(void);
extern u8 get_turing_finger_flag(void);
extern u8 is_in_config_network_state(void);
extern u32 timer_get_ms(void);

#ifdef CONFIG_PAGE_TURNING_DET_ENABLE
static jl_ptd_t  jl_ptd;
static u32 page_tri_time;
static u8 page_tri;
#endif

#ifdef CONFIG_TURING_PAGE_TURNING_DET_ENABLE
static MotionDetection md;
#endif

#ifdef CONFIG_QR_CODE_NET_CFG

static void *qr_decoder;
static u8 qr_flag;

#ifdef CONFIG_TURING_SDK_ENABLE
static char turing_openid[12];

const char *get_qrcode_result_openid(void)
{
    return turing_openid[0] ? turing_openid : NULL;
}
#endif

void qr_code_net_cfg_start(void)
{
#ifdef CONFIG_TURING_SDK_ENABLE
    memset(turing_openid, 0, sizeof(turing_openid));
#endif
    qr_flag = 1;
    qr_decoder = qrcode_init(QR_FRAME_W, QR_FRAME_H, QR_FRAME_W, QRCODE_MODE_NORMAL, SYM_QRCODE, 1, 60, 0, 0, 150);
    /* qr_decoder = qrcode_init(QR_FRAME_W, QR_FRAME_H, QR_FRAME_W, QRCODE_MODE_NORMAL, SYM_BARCODE, 1, 60, 0, 0, 150); */
}

void qr_code_net_cfg_stop(void)
{
    if (qr_decoder) {
        qrcode_deinit(qr_decoder);
        qr_decoder = NULL;
    }
}
static int qrcode_other_type_find(const char *str, const char **ssid, const char **pwd)//配网二维码其他类型查找
{
    if (!str || !ssid || !pwd) {
        return 0;
    }
    const char *p, *e, *s;
    char *fs = NULL, *fp = NULL;
    const char *keyword[] = {
        //WIFI   ssid  pwd   end;
        "WIFI:", "S:", "P:", ";",//huawei,xiaomi: WIFI:T:WPA;S:GJ1;P:8888888899;;
        NULL, NULL, NULL, NULL,
    };
    *pwd = *ssid = NULL;
    for (int i = 0; keyword[i] != NULL; i += 4) {
        p = strstr(str, keyword[i]);
        if (p) {
            p = strstr(p + strlen(keyword[i]), keyword[i + 3]);//查找WIFI的结束符
            if (p) {
                for (int j = 1; j <= 2; j++) {//j=1,ssid; j=2,pwd
                    s = strstr(p, keyword[i + j]);//查找ssid/pwd起始符
                    if (s) {
                        s += strlen(keyword[i + j]);
                        e = strstr(s, keyword[i + 3]);//查找ssid/pwd结束符
                        if (e && (e - s) > 0) {
                            if (j == 1) {
                                fs = (char *)&s[e - s];
                                *ssid = s;
                            } else {
                                fp = (char *)&s[e - s];
                                *pwd = s;
                            }
                        }
                    }

                }
            }
        }
        if (fs) {
            *fs = 0;
            if (fp) {
                *fp = 0;
            }
            return 1;
        }
    }
    return 0;
}
static int qr_code_net_cfg_process(void *qr_decoder, u8 *inputFrame)
{
    int ret = -1, type = 0;
    int enc_type = 0;
    char *buf = NULL;
    int buf_size = 0;
    int md_detected = 0; //是否检测到运动物体
    json_object *new_obj = NULL;
    json_object *key = NULL;

    if (qr_decoder)  {
        qrcode_detectAndDecode(qr_decoder, inputFrame, &md_detected);

        ret = qrcode_get_result(qr_decoder, &buf, &buf_size);
        type = qrcode_get_symbol_type(qr_decoder);

        if (buf_size > 0 && ret == 0) {
            buf[buf_size] = 0;
#ifdef CONFIG_TURING_SDK_ENABLE
            unsigned long olen = 0;
            ret = mbedtls_base64_decode((u8 *)buf, strlen(buf), &olen, (u8 *)buf, strlen(buf));
            if (ret) {
                return -1;
            }
            buf[olen] = 0;
#endif
            printf("qr code type = %d decode: %s\n", type, buf);
            const char *str_ssid = NULL, *str_pwd = NULL;
            new_obj = json_tokener_parse(buf);
            if (!new_obj) {
                goto qr_other;
            }
            str_ssid = json_object_get_string(json_object_object_get(new_obj, "ssid"));
            if (!str_ssid) {
                goto qr_other;
            }
            printf("qr code net config ssid : %s\n", str_ssid);
#ifdef CONFIG_TURING_SDK_ENABLE
            const char *openid = json_object_get_string(json_object_object_get(new_obj, "TuringBindID"));
            if (openid) {
                snprintf(turing_openid, sizeof(turing_openid), "%s", openid);
            }

            str_pwd = json_object_get_string(json_object_object_get(new_obj, "pwd"));
#else
            str_pwd = json_object_get_string(json_object_object_get(new_obj, "pass"));
#endif

qr_other:
            if (!str_ssid) {
                if (!qrcode_other_type_find(buf, &str_ssid, &str_pwd)) {
                    goto __exit;
                }
            }
            if (str_pwd) {
                printf("qr code net config pwd : %s\n", str_pwd);
            } else {
                str_pwd = "";
            }

            qr_code_net_set_ssid_pwd(str_ssid, str_pwd);
            ret = 0;
            qr_flag = 0;
        }
    }

__exit:
    if (new_obj) {
        json_object_put(new_obj);
    }

    return ret;
}

static void cvHalfYUV420(unsigned char *dataSrc, unsigned char *dataDst, int srcHeight, int srcWidth)
{
    //support YUV420
    int i = 0;
    for (int y = 0; y < srcHeight; y += 2) {
        for (int x = 0; x < srcWidth; x += 2) {
            dataDst[i] = dataSrc[y * srcWidth + x];
            i++;
        }
    }
    for (int y = 0; y < srcHeight / 2; y += 2) {
        for (int x = 0; x < srcWidth; x += 4) {
            dataDst[i] = dataSrc[(srcWidth * srcHeight) + (y * srcWidth) + x];
            i++;
            dataDst[i] = dataSrc[(srcWidth * srcHeight) + (y * srcWidth) + (x + 1)];
            i++;
        }
    }
}
#endif

static void get_one_frame(u8 *inputFrame, u32 len, int width, int height)
{
#ifdef CONFIG_QR_CODE_NET_CFG
    if (is_in_config_network_state()) {
        if (qr_decoder && qr_flag) {
#ifdef CONFIG_VIDEO_720P
            extern int YUV420p_Soft_Scaling(unsigned char *src, unsigned char *out, int src_w, int src_h, int out_w, int out_h);
            extern int YUV420p_Cut(unsigned char *yuv420p, int src_w, int src_h, unsigned char *out, int out_size, int w_start, int w_size, int h_start, int h_size);
#if 1
            YUV420p_Soft_Scaling(inputFrame, inputFrame, width, height, width / 4, height / 3);
#else
            YUV420p_Cut(inputFrame, width, height, inputFrame, height * width * 3 / 2, (width -  width / 4) / 2, width / 4, (height - height / 3) / 2, height / 3);
#endif
#else
            cvHalfYUV420(inputFrame, inputFrame, height, width);
#endif
            qr_code_net_cfg_process(qr_decoder, inputFrame);
        }
    }
#endif

#ifdef CONFIG_PAGE_TURNING_DET_ENABLE
    if (page_turning_get_mode() == PICTURE_DET_ENTER_MODE && ptd_process(&jl_ptd, inputFrame)) {
        page_tri = 1;
        page_tri_time = timer_get_ms();
    }
#endif

#ifdef CONFIG_TURING_PAGE_TURNING_DET_ENABLE
    if (page_turning_get_mode() == PICTURE_DET_ENTER_MODE) {
        u8 ocr_flag = get_turing_ocr_flag();
        u8 finger_flag = get_turing_finger_flag();
        unsigned char *outImg = getMotionResult(&md, inputFrame, width, height, 1, TL_CV_YUV2GRAY_420, timer_get_ms(), ocr_flag, finger_flag);
        if (outImg) {
            struct jpeg_encode_req req = {0};
            u32 buf_len = ocr_flag ? 60 * 1024 : 30 * 1024;
            u8 *jpg_img = malloc(buf_len);
            if (!jpg_img) {
                puts("jpeg buf not enough !!!\n");
                return;
            }

            //q >=2 , size  = w*h*q*0.32
            req.q = 5;	//jepg编码质量(范围0-13),质量越好,下面的编码buf需要适当增大
            req.format = JPG_SAMP_FMT_YUV420;
            req.data.buf = jpg_img;
            req.data.len = buf_len;
            req.width = ocr_flag ? width : (width / 2);
            req.height = ocr_flag ? height : (height / 2);
            req.y = outImg;
            req.u = req.y + req.width * req.height;
            req.v = req.u + req.width * req.height / 4;

            if (0 == jpeg_encode_one_image(&req)) {
                printf("jpeg_encode_one_image ok \n\n");
                if (0 != page_turning_recognition(req.data.buf, req.data.len, 0)) {
                    free(jpg_img);
                }
            }
        }
    }
#endif
}

int page_turning_det_init(void)
{
    puts("page_turning_det_init...\n\n");

#ifdef CONFIG_PAGE_TURNING_DET_ENABLE
    int width = YUV_DATA_WIDTH;    //输入源宽度
    int height = YUV_DATA_HEIGHT;   //输入源高度

    int roi_x = 0;      //检测区域X
    int roi_y = 240;    //检测区域Y
    int roi_w = 480;    //检测区域W
    int roi_h = 240;   //检测区域H

    int image_offset = roi_y * 640 + roi_x;
    int hstep = 4;      //检测跳跃水平像素点,
    int vstep = 4;      //检测跳跃垂直像素点,
    int erode_times = 3;    //灵敏度,越小越灵敏
    int max_frame_cnt = 3;  //隔开(n-2)帧检测一次
    int motion_th = 10;     //多少个像素点移动视为有翻页

    ptd_init(&jl_ptd, image_offset, roi_w, roi_h, width, max_frame_cnt, motion_th, erode_times, hstep, vstep);
#endif

#ifdef CONFIG_TURING_PAGE_TURNING_DET_ENABLE
    int min_thr = 30;
    int max_thr = 100;
    int minThrWaitTime = 100;
    int dstHeight = 100;
    int cropRate = 33;
    int serverWaitTime = 0; // 说明：如果室1000ms内只能向服务器发送1次
    int timer = 100;// 单位毫秒
    long long nowTime = timer_get_ms();// 毫秒级的时间戳
    initMotionDetection(&md, min_thr, max_thr, minThrWaitTime, dstHeight, cropRate, serverWaitTime, timer, nowTime);
#endif

    get_yuv_init(get_one_frame);

    return 0;
}

int page_turning_det_uninit(void)
{
    get_yuv_uninit();
#ifdef CONFIG_PAGE_TURNING_DET_ENABLE
    ptd_deinit(&jl_ptd);
#endif
#ifdef CONFIG_TURING_PAGE_TURNING_DET_ENABLE
    cvFreeImageTL(md.frame1);
#endif
    return 0;
}

#ifdef CONFIG_QR_CODE_NET_CFG
void config_network_get_yuv_init(void)
{
    get_yuv_init(get_one_frame);
}

void config_network_get_yuv_uninit(void)
{
    get_yuv_uninit();
}
#endif

static u32(*video_rt_cb)(void *, u8 *, u32);
static void *cb_priv;

void set_video_rt_cb(u32(*cb)(void *, u8 *, u32), void *priv)
{
    video_rt_cb = cb;
    cb_priv = priv;
}

static void *video_rt_usr_init(const char *path, const char *mode)
{
    //连接服务器操作
    puts("video_rt_usr_init\n");

    struct rt_stream_info *r_info = calloc(1, sizeof(struct rt_stream_info));
    if (r_info == NULL) {
        printf("%s malloc fail\n", __FILE__);
        return NULL;
    }

    return (void *)r_info;
}

static int video_rt_usr_send(void *hdr, void *data, u32 len, u8 type)
{
    struct rt_stream_info *r_info = (struct rt_stream_info *)hdr;

    if (video_rt_cb) {
        video_rt_cb(cb_priv, data, len);
    }

#ifdef CONFIG_PAGE_TURNING_DET_ENABLE
    static u32 recognition_time = 0;
    static u32 timehdl;
    u32 dtime;

    if (type == JPEG_TYPE_VIDEO && page_turning_get_mode() == PICTURE_DET_ENTER_MODE) {
        if (page_tri) {
            dtime = timer_get_ms() - page_tri_time;
            //翻页时间已经过去500s并且上次距离上次识别已经过去500ms
            if (dtime > 500 && (timer_get_ms() - recognition_time) > 500) {
                if (0 == page_turning_recognition(data, len, 1)) {
                    recognition_time = timer_get_ms();
                    page_tri = 0;
                }
            }
        }
    }
#endif

    return len;
}

static int video_rt_usr_uninit(void *hdr)
{
    puts("video_rt_usr_uninit\n\n\n\n\n\n");
    struct rt_stream_info *r_info = (struct rt_stream_info *)hdr;
    free(r_info);
    return 0;
}

REGISTER_NET_VIDEO_STREAM_SUDDEV(usr_video_stream_sub) = {
    .name = "usr",
    .open =  video_rt_usr_init,
    .write = video_rt_usr_send,
    .close = video_rt_usr_uninit,
};

#endif

